/* =============================================================
 * SmallSQL : a free Java DBMS library for the Java(tm) platform
 * =============================================================
 *
 * (C) Copyright 2004-2007, by Volker Berlin.
 *
 * Project Info:  http://www.smallsql.de/
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 *
 * ---------------
 * SQLParser.java
 * ---------------
 * Author: Volker Berlin
 * 
 */
package smallsql.database;

import java.util.List;
import java.sql.*;
import smallsql.database.language.Language;

final class SQLParser {

	private static final int Where = 0;
	private static final int[] MISSING_EXPRESSION = null;
	SSConnection con;
	private char[] sql;
    private List tokens;
    private int tokenIdx;

    Command parse(SSConnection con, String sqlString) throws SQLException{
    	this.con = con;
        Command cmd = parse( sqlString.toCharArray() );
        SQLToken token = nextToken();
        if(token != null){
        	throw createSyntaxError(token, Language.STXADD_ADDITIONAL_TOK);
        }
        return cmd;
    }
    
//    final private Command parse(char[] sql) throws SQLException{
//        this.sql = sql;
//        this.tokens = SQLTokenizer.parseSQL( sql );
//        tokenIdx = 0;
//
//     //   SQLToken token = nextToken(COMMANDS);
////        switch (token.value){
////            case smallsql.database.SELECT:
////                    return select();
////            case smallsql.database.DELETE:
////                    return delete();
////            case smallsql.database.INSERT:
////                    return insert();
////            case smallsql.database.UPDATE:
////                    return update();
////            case smallsql.database.CREATE:
////                    return create();
////            case smallsql.database.DROP:
////                    return drop();
////            case smallsql.database.ALTER:
////                    return alter();
////            case smallsql.database.SET:
////                    return set();
////			case smallsql.database.USE:
////					token = nextToken(MISSING_EXPRESSION);
////					String name = token.getName( sql );
////					checkValidIdentifier( name, token );
////					CommandSet set = new CommandSet( con.log, smallsql.database.USE);
////					set.name = name;
////					return set;
////            case smallsql.database.EXECUTE:
////                    return execute();
////            case smallsql.database.TRUNCATE:
////            		return truncate();
////            default:
////                    throw new Error();
////        }
//    }
    
    
    private Command parse(char[] charArray) {
		// TODO Auto-generated method stub
		return null;
	}

	Expression parseExpression(String expr) throws SQLException{
		this.sql = expr.toCharArray();
		this.tokens = SQLTokenizer.parseSQL( sql );
		tokenIdx = 0;
    	return expressionSingle( null, 0);
    }

    private Expression expressionSingle(Object object, int i) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * Create a syntax error message, using a custom message.
	 * 
	 * @param token
	 *            token object; if not null, generates a SYNTAX_BASE_OFS,
	 *            otherwise a SYNTAX_BASE_END.
	 * @param addMessage
	 *            additional message object to append.
	 */
    private SQLException createSyntaxError(SQLToken token, String addMessageCode) {
    	String message = getErrorString(token, addMessageCode, null);
    	return SmallSQLException.create(Language.CUSTOM_MESSAGE);
    }
    
    /**
	 * Create a syntax error message, using a message with a parameter.
	 * 
	 * @param token
	 *            token object; if not null, generates a SYNTAX_BASE_OFS,
	 *            otherwise a SYNTAX_BASE_END.
	 * @param addMessageCode
	 *            additional message[Code] to append.
	 * @param param0
	 *            parameter.
	 */
    private SQLException createSyntaxError(SQLToken token, String addMessageCode, 
    		Object param0) {
    	String message = getErrorString(token, addMessageCode, param0);
    	return SmallSQLException.create(Language.CUSTOM_MESSAGE);
    }
    
    /**
	 * Create an "Additional keyword required" syntax error.
	 * 
	 * @param token
	 *            token object.
	 * @param validValues
	 *            valid values.
	 * @return Exception.
	 */
    private SQLException createSyntaxError(SQLToken token, int[] validValues){
    	String msgStr = SmallSQLException.translateMsg(
    			Language.STXADD_KEYS_REQUIRED, new Object[] { });
    	
    	StringBuffer msgBuf = new StringBuffer( msgStr );

        for(int i=0; i<validValues.length; i++){
            String name = SQLTokenizer.getKeyWord(validValues[i]);
            if(name == null) name = String.valueOf( (char)validValues[i] );
            msgBuf.append( name );
            if (i < validValues.length - 2)
                msgBuf.append( ", ");
            else
            if ( i == validValues.length - 2 )
                msgBuf.append( " or ");
        }

    	String message = getErrorString(
    			token, Language.CUSTOM_MESSAGE, msgBuf);
    	return SmallSQLException.create(Language.CUSTOM_MESSAGE);
    }

    /**
	 * Create the complete error string (begin + middle + end).
	 * 
	 * @param token
	 *            token object.
	 * @param middleMsgCode
	 *            middle message[code].
	 * @param middleMsgParam
	 *            middle message[code] parameter.
	 * @return complete error message string.
	 */
    private String getErrorString(SQLToken token, String middleMsgCode, 
    		Object middleMsgParam) {
    	StringBuffer buffer = new StringBuffer(1024);

    	/* begin */
    	
        if(token != null){
        	Object[] params = { String.valueOf(token.offset),
        						String.valueOf(sql, token.offset, token.length) };
        	String begin = SmallSQLException.translateMsg(Language.SYNTAX_BASE_OFS, params);
        	buffer.append(begin);
        }
        else{
        	String begin = SmallSQLException.translateMsg(
        			Language.SYNTAX_BASE_END, new Object[] { });
        	buffer.append(begin);
        }
    	
    	/* middle */
    	
    	String middle = SmallSQLException.translateMsg(
    			middleMsgCode, new Object[] { middleMsgParam });
    	
    	buffer.append(middle);
    	
    	/* end */
    	
        int valOffset = (token != null) ? token.offset : sql.length;
        int valBegin = Math.max( 0, valOffset-40);
        int valEnd   = Math.min( valOffset+20, sql.length );
        String lineSeparator = System.getProperty( "line.separator" );
        buffer.append( lineSeparator );
        buffer.append( sql, valBegin, valEnd-valBegin);
        buffer.append( lineSeparator );
        for(; valBegin<valOffset; valBegin++) buffer.append(' ');
        buffer.append('^');
    	
    	return buffer.toString();    	
    }
    
    private void checkValidIdentifier(String name, SQLToken token) throws SQLException{
//        if(token.value == smallsql.database.ASTERISK) return;
//        if(token.value != smallsql.database.VALUE &&
//		   token.value != smallsql.database.IDENTIFIER &&
//           token.value < 200){
//            throw createSyntaxError( token, Language.STXADD_IDENT_EXPECT);
//        }
        if(name.length() == 0) {
            throw createSyntaxError( token, Language.STXADD_IDENT_EMPTY, name);
        }
        char firstChar = name.charAt(0);
		if(firstChar != '#' && firstChar < '@') {
			throw createSyntaxError( token, Language.STXADD_IDENT_WRONG, name );
		}
    }
    
	/**
     * Returns a valid identifier from this token.
     * @param token the token of the identifier
     * @return the string with the name
     * @throws SQLException if the identifier is invalid
     */
    private String getIdentifier(SQLToken token) throws SQLException{
    	String name = token.getName(sql);
    	checkValidIdentifier( name, token );
    	return name;
    }
    
    
    /**
     * Returns a valid identifier from the next token from token stack.
     * @return the string with the name
     * @throws SQLException if the identifier is invalid
     */
//    private String nextIdentifier() throws SQLException{
//    	int[] MISSING_IDENTIFIER;
//		return getIdentifier( nextToken( MISSING_IDENTIFIER ) );
//    }
    
    
    /**
     * Check if the identifier is a 2 part name with a point in the middle like FIRST.SECOND
     * @param name the name of the first part
     * @return the second part if exist else returns the first part
     * @throws SQLException 
     */
    private String nextIdentiferPart(String name) throws SQLException{
        SQLToken token = nextToken();
        //check if the object name include a database name
//        if(token != null && token.value == smallsql.database.POINT){
//            return nextIdentifier();
//        }else{
//            previousToken();
//        }
        return name;
    }
    
    
    final private boolean isKeyword(SQLToken token){
    	if(token == null) return false;
//    	switch(token.value){
//    		case smallsql.database.SELECT:
//    		case smallsql.database.INSERT:
//    		case smallsql.database.UPDATE:
//    		case smallsql.database.UNION:
//    		case smallsql.database.FROM:
//    		case smallsql.database.WHERE:
//    		case smallsql.database.GROUP:
//    		case smallsql.database.HAVING:
//			case smallsql.database.ORDER:
//    		case smallsql.database.COMMA:
//			case smallsql.database.SET:
//            case smallsql.database.JOIN:
//            case smallsql.database.LIMIT:
//    			return true;
//    	}
    	return false;
    }
    
	/** 
	 * Return the last token that the method nextToken has return
	 */
	private SQLToken lastToken(){
		if(tokenIdx > tokens.size()){
			return null;
		}
		return (SQLToken)tokens.get( tokenIdx-1 );
	}
    private void previousToken(){
        tokenIdx--;
    }

    private SQLToken nextToken(){
        if(tokenIdx >= tokens.size()){
            tokenIdx++; // must be ever increment that the method previousToken() is working
            return null;
        }
        return (SQLToken)tokens.get( tokenIdx++ );
    }

    private SQLToken nextToken( int[] validValues) throws SQLException{
        SQLToken token = nextToken();
        if(token == null) throw createSyntaxError( token, validValues);
        if(validValues == MISSING_EXPRESSION){
            return token; // an expression can be contained in every token.
        }
//        if(validValues == MISSING_IDENTIFIER){
//            // the follow token are not valid identifier
//            switch(token.value){
//                case smallsql.database.PARENTHESIS_L:
//                case smallsql.database.PARENTHESIS_R:
//                case smallsql.database.COMMA:
//                    throw createSyntaxError( token, validValues);
//            }
//            return token;
//        }
        for(int i=validValues.length-1; i>=0; i--){
            if(token.value == validValues[i]) return token;
        }
        throw createSyntaxError( token, validValues);
    }
    

    /**
     * A single SELECT of a UNION or only a simple single SELECT.
     * @return
     * @throws SQLException
     */
//    private CommandSelect singleSelect() throws SQLException{
//        CommandSelect selCmd = new CommandSelect(con.log);
//		SQLToken token;
//        // scan for prefix like DISTINCT, ALL and the TOP clause; sample: SELECT TOP 15 ...
////Switch: while(true){
////			token = nextToken(MISSING_EXPRESSION);
////			switch(token.value){
////				case smallsql.database.TOP:
////					token = nextToken(MISSING_EXPRESSION);
////					try{
////						int maxRows = Integer.parseInt(token.getName(sql));
////						selCmd.setMaxRows(maxRows);
////					}catch(NumberFormatException e){
////						throw createSyntaxError(token, Language.STXADD_NOT_NUMBER, token.getName(sql));
////					}
////					break;
////				case smallsql.database.ALL:
////					selCmd.setDistinct(false);
////					break;
////				case smallsql.database.DISTINCT:
////					selCmd.setDistinct(true);
////					break;
////				default:
////					previousToken();
////					break Switch;
////			}
////		}
//
//        while(true){
//            Expression column = expressionSingle(selCmd, 0);
//            selCmd.addColumnExpression( column );
//
//            token = nextToken();
//            if(token == null) return selCmd; // SELECT without FROM
//
//            boolean as = false;
////            if(token.value == smallsql.database.AS){
////                token = nextToken(MISSING_EXPRESSION);
////                as = true;
////            }
//
//            if(as || (!isKeyword(token))){
//            	String alias = getIdentifier( token);
//                column.setAlias( alias );
//                token = nextToken();
//                if(token == null) return selCmd; // SELECT without FROM
//            }
//
////            switch(token.value){
////                case smallsql.database.COMMA:
////                        if(column == null) throw createSyntaxError( token, MISSING_EXPRESSION );
////                        column = null;
////                        break;
////                case smallsql.database.FROM:
////                        if(column == null) throw createSyntaxError( token, MISSING_EXPRESSION );
////                        column = null;
////                        from(selCmd);
////                        return selCmd;
////
////                default:
////                        if(!isKeyword(token))
////                			throw createSyntaxError( token, new int[]{smallsql.database.COMMA, smallsql.database.FROM} );
////                        previousToken();
////                        return selCmd;
////            }
//        }
//    }
    
    
//    final private CommandSelect select() throws SQLException{
//		CommandSelect selCmd = singleSelect();
//		SQLToken token = nextToken();
//		   		
//    	UnionAll union = null; 
//	
////		while(token != null && token.value == smallsql.database.UNION){
////			if(union == null){
////				union = new UnionAll();
////				union.addDataSource(new ViewResult( con, selCmd ));
////				selCmd = new CommandSelect(con.log);
////				selCmd.setSource( union );
////				DataSources from = new DataSources();
////				from.add(union);
////				selCmd.setTables( from );
////				selCmd.addColumnExpression( new ExpressionName("*") );
////			}
////			nextToken(MISSING_ALL);
////			nextToken(MISSING_SELECT);
////			union.addDataSource( new ViewResult( con, singleSelect() ) );
////			token = nextToken();
////		}
////		if(token != null && token.value == smallsql.database.ORDER){
////			order( selCmd );
////			token = nextToken();
////		}
////		if(token != null && token.value == smallsql.database.LIMIT){
////            limit( selCmd );
////            token = nextToken();
////        }
//        previousToken();
//		return selCmd;
//    }


//    private Command delete() throws SQLException{
//    	CommandDelete cmd = new CommandDelete(con.log);
//    	nextToken(MISSING_FROM);
//    	from(cmd);
//		SQLToken token = nextToken();
//		if(token != null){
//			if(token.value != smallsql.database.WHERE)
//				throw this.createSyntaxError(token, MISSING_WHERE);
//			where(cmd);
//		}
//		return cmd;
//    }


//	private Command truncate() throws SQLException{
//		CommandDelete cmd = new CommandDelete(con.log);
//		nextToken(MISSING_TABLE);
//		from(cmd);
//		return cmd;
//	}


//    private Command insert() throws SQLException{
//        SQLToken token = nextToken( MISSING_INTO );
//        CommandInsert cmd = new CommandInsert( con.log, nextIdentifier() );
//
//		int parthesisCount = 0;
//
//		token = nextToken(MISSING_PARENTHESIS_VALUES_SELECT);
//        if(token.value == smallsql.database.PARENTHESIS_L){
//        	token = nextToken(MISSING_EXPRESSION);
//        	if(token.value == smallsql.database.SELECT){
//				parthesisCount++;
//				cmd.noColumns = true;
//        	}else{
//				previousToken();
//	            Expressions list = expressionParenthesisList(cmd);
//	            for(int i=0; i<list.size(); i++){
//	                cmd.addColumnExpression( list.get( i ) );
//	            }
//	            token = nextToken(MISSING_PARENTHESIS_VALUES_SELECT);
//        	}
//        }else cmd.noColumns = true;
//        
////Switch: while(true)
////        switch(token.value){
////        	case smallsql.database.VALUES:{
////	            token = nextToken(MISSING_PARENTHESIS_L);
////	            cmd.addValues( expressionParenthesisList(cmd) );
////	            return cmd;
////	        }
////        	case smallsql.database.SELECT:
////        		cmd.addValues( select() );
////        		while(parthesisCount-- > 0){
////        			nextToken(MISSING_PARENTHESIS_R);
////        		}
////        		return cmd;
////        	case smallsql.database.PARENTHESIS_L:
////        		token = nextToken(MISSING_PARENTHESIS_VALUES_SELECT);
////        		parthesisCount++;
////        		continue Switch;
////        	default:
////        		throw new Error();
////        }
//    }


    private Command update() throws SQLException{
		CommandUpdate cmd = new CommandUpdate(con.log);
		// read table name
		DataSources tables = new DataSources();
		cmd.setTables( tables );
		cmd.setSource( rowSource( cmd, tables, 0 ) );
		
//		SQLToken token = nextToken(MISSING_SET);
//		while(true){
//			token = nextToken();
//			Expression dest = expressionSingle( cmd, token);
//			if(dest.getType() != Expression.NAME) throw createSyntaxError( token, MISSING_IDENTIFIER );
//			nextToken(MISSING_EQUALS);
//			Expression src = expression(cmd, 0);
//			cmd.addSetting( dest, src);
//			token = nextToken();
//			if(token == null) break;
//			switch(token.value){
//				case smallsql.database.WHERE:
//					where(cmd);
//					return cmd;				
//				case smallsql.database.COMMA:
//					continue;
//				default: throw createSyntaxError( token, MISSING_WHERE_COMMA );
//			}
//		}
		return cmd;
    }


//    private Command create() throws SQLException{
//        while(true){
//            SQLToken token = nextToken(COMMANDS_CREATE);
//            switch(token.value){
//                case smallsql.database.DATABASE:
//                    return createDatabase();
//                case smallsql.database.TABLE:
//                    return createTable();
//                case smallsql.database.VIEW:
//                    return createView();
//                case smallsql.database.INDEX:
//                    return createIndex(false);
//                case smallsql.database.PROCEDURE:
//                    return createProcedure();
//                case smallsql.database.UNIQUE:
//                    do{
//                        token = nextToken(COMMANDS_CREATE_UNIQUE);
//                    }while(token.value == smallsql.database.INDEX);
//                    return createIndex(true);
//                case smallsql.database.NONCLUSTERED:
//                case smallsql.database.CLUSTERED:
//                    continue;
//                default:
//                    throw createSyntaxError( token, COMMANDS_CREATE );
//            }
//        }
//    }
	

    private CommandCreateDatabase createDatabase() throws SQLException{
        SQLToken token = nextToken();
        if(token == null) throw createSyntaxError( token, MISSING_EXPRESSION );
        return new CommandCreateDatabase( con.log, token.getName(sql));
    }
	
    
//    private CommandTable createTable() throws SQLException{
//        String catalog;
//        String tableName = catalog = nextIdentifier();
//        tableName = nextIdentiferPart(tableName);
//        if(tableName == catalog) catalog = null;
//   //     CommandTable cmdCreate = new CommandTable( con.log, catalog, tableName, CommandTable );
//  //      SQLToken token = nextToken( MISSING_PARENTHESIS_L );
//
////        nextCol:
////        while(true){
////            token = nextToken( MISSING_EXPRESSION );
////			
////			String constraintName;
////            if(token.value == smallsql.database.CONSTRAINT){
////            	// reading a CONSTRAINT with name
////		    	constraintName = nextIdentifier();
////				token = nextToken( MISSING_KEYTYPE );
////            }else{
////				constraintName = null;
////            }
////			switch(token.value){
////				case smallsql.database.PRIMARY:
////				case smallsql.database.UNIQUE:
////				case smallsql.database.FOREIGN:
////					IndexDescription index = index(cmdCreate, token.value, tableName, constraintName, null);
////                    if(token.value == smallsql.database.FOREIGN){
////                        nextToken( MISSING_REFERENCES );
////                        String pk = nextIdentifier();
////                        Expressions expressions = new Expressions();
////                        Strings columns = new Strings();
////                        expressionDefList( cmdCreate, expressions, columns );
////                        IndexDescription pkIndex = new IndexDescription( null, pk, smallsql.database.UNIQUE, expressions, columns);
////                        ForeignKey foreignKey = new ForeignKey(pk, pkIndex, tableName, index);
////                        cmdCreate.addForeingnKey(foreignKey);
////                    }else{
////                        cmdCreate.addIndex( index );
////                    }
////	
////					token = nextToken( MISSING_COMMA_PARENTHESIS );
////					switch(token.value){
////						case smallsql.database.PARENTHESIS_R:
////							return cmdCreate;
////						case smallsql.database.COMMA:
////							continue nextCol;
////					}
////            }
////            // the token is a column name
////			token = addColumn( token, cmdCreate );
////            if(token == null){
////                throw createSyntaxError(token, MISSING_COMMA_PARENTHESIS);
////            }
////            switch(token.value){
////                case smallsql.database.PARENTHESIS_R:
////                    return cmdCreate;
////                case smallsql.database.COMMA:
////                    continue nextCol;
////                default:
////                    throw createSyntaxError(token, MISSING_COMMA_PARENTHESIS);
////            }
////        }
//    }
    
	
    private String nextIdentifier() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
     * Parse a Column and add it to the Command. If the column is unique or primary
     * then an index is added.
     * @param token the SQLToken with the column name
     * @return the token of the delimiter
     */
//    private SQLToken addColumn(SQLToken token, CommandTable cmdCreate) throws SQLException{
//        String colName = getIdentifier( token );
//        Column col = datatype(false);
//        col.setName( colName );
//
//		token = nextToken();
//        boolean nullableWasSet = false;
//        boolean defaultWasSet = col.isAutoIncrement(); // with data type COUNTER already this value is set
//        while(true){
//            if(token == null){
//                cmdCreate.addColumn( col );
//                return null;
//            }
////            switch(token.value){
////                case smallsql.database.PARENTHESIS_R:
////                case smallsql.database.COMMA:
////                    cmdCreate.addColumn( col );
////                    return token;
////                case smallsql.database.DEFAULT:
////                    if(defaultWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
////					int offset = token.offset + token.length;
////                    token = nextToken();
////                    if(token != null) offset = token.offset;
////					previousToken();                    
////					Expression expr = expression(cmdCreate, 0);
////					SQLToken last = lastToken();
////					int length = last.offset + last.length - offset;
////					String def = new String( sql, offset, length );
////                    col.setDefaultValue( expr, def );
////                    defaultWasSet = true;
////                    break;
////                case smallsql.database.IDENTITY:
////                    if(defaultWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
////                    col.setAutoIncrement(true);
////                    defaultWasSet = true;
////                    break;
////                case smallsql.database.NULL:
////                    if(nullableWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
////                    //col.setNullable(true); is already default
////                    nullableWasSet = true;
////                    break;
////                case smallsql.database.NOT:
////                    if(nullableWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
////                    token = nextToken( MISSING_NULL );
////                    col.setNullable(false);
////                    nullableWasSet = true;
////                    break;
////				case smallsql.database.PRIMARY:
////				case smallsql.database.UNIQUE:
////					IndexDescription index = index(cmdCreate, token.value, cmdCreate.name, null, colName);
////					cmdCreate.addIndex( index );
////					break;
////                default:
////                    throw createSyntaxError(token, MISSING_OPTIONS_DATATYPE);
////            }
//            token = nextToken();
//        }
//    }
//    

	/**
	 * Parse construct like:<br>
	 * <li>PRIMARY KEY (col1)
	 * <li>UNIQUE (col1, col2)
	 * <li>FOREIGN KEY REFERENCES ref_table(col1)
	 * @param cmd
	 * @param constraintType one of SQLTokenizer.PRIMARY, SQLTokenizer.UNIQUE or SQLTokenizer.FOREIGN.
	 * @param if it a constrain of the current column else null
	 * @return a new IndexDescription
	 */
//	private IndexDescription index(Command cmd, int constraintType, String tableName, String contrainName, String columnName) throws SQLException{
//		if(constraintType != smallsql.database.UNIQUE) nextToken( MISSING_KEY );
//		SQLToken token = nextToken();
//        if(token != null){
//    		switch(token.value){
//    			case smallsql.database.CLUSTERED:
//    			case smallsql.database.NONCLUSTERED:
//    				// ignoring, this tokens form MS SQL Server are ignored
//    				break;
//                default:
//                    previousToken();
//    		}
//        }else{
//            previousToken();
//        }
//		Strings columns = new Strings();
//		Expressions expressions = new Expressions();
//		if(columnName != null){
//			//Constraint for a single column together with the column definition
//			columns.add(columnName);
//			expressions.add(new ExpressionName(columnName));
//		}else{
//			//Constraint as addition definition
//            expressionDefList( cmd, expressions, columns );
//		}
//		return new IndexDescription( contrainName, tableName, constraintType, expressions, columns);
//	}


    /**
     * Read a DataTpe description. This is used for CREATE TABLE and CONVERT function. 
     * @param isEscape true then the data types start with "SQL_". This is used for the Escape Syntax.
     */
//    private Column datatype(boolean isEscape) throws SQLException{
//		SQLToken token;
//		int dataType;
//		if(isEscape){
//			token = nextToken( MISSING_SQL_DATATYPE );
//			switch(token.value){
//				case smallsql.database.SQL_BIGINT: 			dataType = smallsql.database.BIGINT;		break;
//				case smallsql.database.SQL_BINARY:			dataType = smallsql.database.BINARY; 	break;
//				case smallsql.database.SQL_BIT:				dataType = smallsql.database.BIT;		break;
//				case smallsql.database.SQL_CHAR:				dataType = smallsql.database.CHAR;		break;
//				case smallsql.database.SQL_DATE:				dataType = smallsql.database.DATE;		break;
//				case smallsql.database.SQL_DECIMAL:			dataType = smallsql.database.DECIMAL;	break;
//				case smallsql.database.SQL_DOUBLE:			dataType = smallsql.database.DOUBLE;		break;
//				case smallsql.database.SQL_FLOAT:			dataType = smallsql.database.FLOAT;		break;
//				case smallsql.database.SQL_INTEGER:			dataType = smallsql.database.INT;		break;
//				case smallsql.database.SQL_LONGVARBINARY:	dataType = smallsql.database.LONGVARBINARY;break;
//				case smallsql.database.SQL_LONGVARCHAR:		dataType = smallsql.database.LONGVARCHAR;break;
//				case smallsql.database.SQL_REAL:				dataType = smallsql.database.REAL;		break;
//				case smallsql.database.SQL_SMALLINT:			dataType = smallsql.database.SMALLINT;	break;
//				case smallsql.database.SQL_TIME:				dataType = smallsql.database.TIME;		break;
//				case smallsql.database.SQL_TIMESTAMP:		dataType = smallsql.database.TIMESTAMP;	break;
//				case smallsql.database.SQL_TINYINT:			dataType = smallsql.database.TINYINT;	break;
//				case smallsql.database.SQL_VARBINARY:		dataType = smallsql.database.VARBINARY;	break;
//				case smallsql.database.SQL_VARCHAR:			dataType = smallsql.database.VARCHAR;	break;
//				default: throw new Error();
//			}
//		}else{
//			token = nextToken( MISSING_DATATYPE );
//			dataType = token.value;
//		}
//		Column col = new Column();
//
//		// two-part  data type
//		if(dataType == smallsql.database.LONG){
//			token = nextToken();
//			if(token != null && token.value == smallsql.database.RAW){
//				dataType = smallsql.database.LONGVARBINARY;
//			}else{
//				dataType = smallsql.database.LONGVARCHAR;
//				previousToken();
//			}
//		}
//
//		switch(dataType){
//			case smallsql.database.RAW:
//				dataType = smallsql.database.VARBINARY;
//				// no break;
//			case smallsql.database.CHAR:
//			case smallsql.database.VARCHAR:
//			case smallsql.database.NCHAR:
//			case smallsql.database.NVARCHAR:
//			case smallsql.database.BINARY:
//			case smallsql.database.VARBINARY:
//			{
//				// detect the maximum column size
//                token = nextToken();
//				int displaySize;
//				if(token == null || token.value != smallsql.database.PARENTHESIS_L){
//					displaySize = 30;
//                    previousToken();
//				}else{
//					token = nextToken( MISSING_EXPRESSION );
//					try{
//						displaySize = Integer.parseInt(token.getName(sql) );
//					}catch(Exception e){
//						throw createSyntaxError(token, MISSING_NUMBERVALUE );
//					}
//					nextToken( MISSING_PARENTHESIS_R );
//				}
//				col.setPrecision( displaySize );
//				break;
//			}
//			case smallsql.database.SYSNAME:
//				col.setPrecision(255);
//				dataType = smallsql.database.VARCHAR;
//				break;
//			case smallsql.database.COUNTER:
//				col.setAutoIncrement(true);
//				dataType = smallsql.database.INT;
//				break;
//			case smallsql.database.NUMERIC:
//			case smallsql.database.DECIMAL:
//                token = nextToken();
//				if(token != null && token.value == smallsql.database.PARENTHESIS_L){
//					// read the precision of the data type
//					token = nextToken( MISSING_EXPRESSION );
//					int value;
//					try{
//						value = Integer.parseInt(token.getName(sql) );
//					}catch(Exception e){
//						throw createSyntaxError(token, MISSING_NUMBERVALUE );
//					}
//					col.setPrecision(value);
//					token = nextToken( MISSING_COMMA_PARENTHESIS );
//					if(token.value == smallsql.database.COMMA){
//						// read the scale of the data type
//						token = nextToken( MISSING_EXPRESSION );
//						try{
//							value = Integer.parseInt(token.getName(sql) );
//						}catch(Exception e){
//							throw createSyntaxError(token, MISSING_NUMBERVALUE );
//						}
//						col.setScale(value);
//						nextToken( MISSING_PARENTHESIS_R );
//					}
//				}else{
//					col.setPrecision(18); //default Precision for decimal and numeric
//                    previousToken();
//				}
//				break;
//		}
//		col.setDataType( dataType );
//		return col;
//    }
////    
//    private CommandCreateView createView() throws SQLException{
//    	String viewName = nextIdentifier();
//
//		int[] MISSING_AS;
//		nextToken(MISSING_AS);
//		int[] MISSING_SELECT;
//		SQLToken token = nextToken(MISSING_SELECT);
//		CommandCreateView cmd = new CommandCreateView( con.log, viewName );
//		
//		cmd.sql = new String(sql, token.offset, sql.length-token.offset );
//		select(); //Parse to check for valid
//        return cmd;
//    }


//    private CommandTable createIndex(boolean unique) throws SQLException{
//        String indexName = nextIdentifier();
//        nextToken(MISSING_ON);
//        String catalog;
//        String tableName = catalog = nextIdentifier();
//        tableName = nextIdentiferPart(tableName);
//        if(tableName == catalog) catalog = null;
//        CommandTable cmd = new CommandTable( con.log, catalog, tableName, smallsql.database.INDEX );
//        Expressions expressions = new Expressions();
//        Strings columns = new Strings();
//        expressionDefList( cmd, expressions, columns );
//        IndexDescription indexDesc = new IndexDescription( 
//                indexName, 
//                tableName, 
//                unique ? smallsql.database.UNIQUE : smallsql.database.INDEX, 
//                        expressions, 
//                        columns);
//        //TODO Create Index
//		Object[] param = { "Create Index" };
//        throw SmallSQLException.create(Language.UNSUPPORTED_OPERATION, param);
//    }

    private CommandCreateDatabase createProcedure() throws SQLException{
        //TODO Create Procedure
		Object[] param = { "Create Procedure" };
    	throw SmallSQLException.create(Language.UNSUPPORTED_OPERATION, param);
    }

//    private Command drop() throws SQLException{
//        SQLToken tokenType = nextToken(COMMANDS_DROP);
//        
//		String catalog;
//		String name = catalog = nextIdentifier();
//        name = nextIdentiferPart( name );
//        if(name == catalog) catalog = null;
//
//        switch(tokenType.value){
//            case smallsql.database.DATABASE:
//            case smallsql.database.TABLE:
//            case smallsql.database.VIEW:
//            case smallsql.database.INDEX:
//            case smallsql.database.PROCEDURE:
//            	return new CommandDrop( con.log, catalog, name, tokenType.value);
//            default:
//                throw createSyntaxError( tokenType, COMMANDS_DROP );
//        }
//    }
//
//
//    private Command alter() throws SQLException{
//    	SQLToken tokenType = nextToken(COMMANDS_ALTER);
//		String catalog;
//		String tableName = catalog = nextIdentifier();
//        switch(tokenType.value){
//        case smallsql.database.TABLE:
//        case smallsql.database.VIEW:
//        case smallsql.database.INDEX:
//        case smallsql.database.PROCEDURE:
//            tableName = nextIdentiferPart(tableName);
//            if(tableName == catalog) catalog = null;
//        }
//        switch(tokenType.value){
//    	//case SQLTokenizer.DATABASE:
//        case smallsql.database.TABLE:
//            return alterTable( catalog, tableName );
//        //case SQLTokenizer.VIEW:
//        //case SQLTokenizer.INDEX:
//        //case SQLTokenizer.PROCEDURE:
//        default:
//    		Object[] param = { "ALTER " + tokenType.getName( sql ) };
//        	throw SmallSQLException.create(Language.UNSUPPORTED_OPERATION, param);
//        }
//    }
//    
//    
//    Command alterTable( String catalog, String name ) throws SQLException{
//    	SQLToken tokenType = nextToken(MISSING_ADD_ALTER_DROP);
//        CommandTable cmd = new CommandTable( con.log, catalog, name, tokenType.value );
//    	switch(tokenType.value){
//    	case smallsql.database.ADD:
//    		SQLToken token;
//    		do{
//    			token = nextToken( MISSING_IDENTIFIER );
//    			token = addColumn( token, cmd );
//    		}while(token != null && token.value == smallsql.database.COMMA );
//
//    		return cmd;
//    	default:
//    		Object[] param = { "ALTER TABLE " + tokenType.getName( sql ) };
//            throw SmallSQLException.create(Language.UNSUPPORTED_OPERATION, param);
//    	}
//    }
//    
//
//    private CommandSet set() throws SQLException{
//        SQLToken token = nextToken( COMMANDS_SET );
//        switch(token.value){
//            case smallsql.database.TRANSACTION:
//                return setTransaction();
//            default:
//                throw new Error();
//        }
//    }

 //   private CommandSet setTransaction() throws SQLException{
 //       SQLToken token = nextToken( MISSING_ISOLATION );
//        token = nextToken( MISSING_LEVEL );
//        token = nextToken( COMMANDS_TRANS_LEVEL );
 //       CommandSet cmd = new CommandSet( con.log, smallsql.database.LEVEL );
//        switch(token.value){
//            case smallsql.database.READ:
//                token = nextToken( MISSING_COMM_UNCOMM );
//                switch(token.value){
//                    case smallsql.database.COMMITTED:
//                        cmd.isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
//                        break;
//                    case smallsql.database.UNCOMMITTED:
//                        cmd.isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
//                        break;
//                    default:
//                        throw new Error();
//                }
//                return cmd;
//            case smallsql.database.REPEATABLE:
//                token = nextToken( MISSING_READ );
//                cmd.isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
//                return cmd;
//            case smallsql.database.SERIALIZABLE:
//                cmd.isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
//                return cmd;
//            default:
//                throw new Error();
//        }


  //  }

    private Command execute() throws SQLException{
        //TODO Execute
        throw SmallSQLException.create(Language.UNSUPPORTED_OPERATION);
    }

    /**
     * Read a Expression list in parenthesis like of VALUES() or functions. 
     * The left parenthesis is already consumed.
     * 
     * @param cmd is needed to add parameters "?" with addParameter() 
     * @see #expressionDefList
     */ 
//    private Expressions expressionParenthesisList(Command cmd) throws SQLException{
//		Expressions list = new Expressions();
//		{
//			SQLToken token = nextToken();
////			if(token != null && token.value == smallsql.database.PARENTHESIS_R){
////				// empty list like functions without parameters
////				return list;
////			}
//			previousToken();
//		}
////        while(true){
////            list.add( expression(cmd, 0) );
////            SQLToken token = nextToken(MISSING_COMMA_PARENTHESIS);
////            switch(token.value){
////                case smallsql.database.PARENTHESIS_R:
////                    return list;
////                case smallsql.database.COMMA:
////                    continue;
////                default:
////                    throw new Error();
////            }
////        }
//    }

    
    /**
     * Read a list of expressions. The list is limit from specific SQL keywords like SELECT, GROUP BY, ORDER BY
     */
//    private Expressions expressionTokenList(Command cmd, int listType) throws SQLException{
//		Expressions list = new Expressions();
//        while(true){
//        	Expression expr = expressionSingle(cmd, 0);
//            list.add( expr );
//            SQLToken token = nextToken();
//            
////			if(listType == smallsql.database.ORDER && token != null){
////				switch(token.value){
////					case smallsql.database.DESC:
////						expr.setAlias(smallsql.database.DESC_STR);
////						//no break;
////					case smallsql.database.ASC:
////						token = nextToken();
////				}				
////			}
//			
//			if(token == null) {
//				previousToken();
//				return list;
//			}
//
////			switch(token.value){
////                case smallsql.database.COMMA:
////                    continue;
////                default:
////					if(isKeyword(token) ){
////						previousToken();
////						return list;
////					}
////                    throw createSyntaxError( token, MISSING_TOKEN_LIST);
////            }
//        }
//    }
    
    
//    private void expressionDefList(Command cmd, Expressions expressions, Strings columns) throws SQLException{
//        SQLToken token = nextToken();
////        if(token.value != smallsql.database.PARENTHESIS_L) throw createSyntaxError(token, MISSING_PARENTHESIS_L );
//        Loop:
//        while(true){
//            int offset = token.offset + token.length;
//            token = nextToken();
//            if(token != null) offset = token.offset;
//            previousToken();  
//            
//            expressions.add( expressionSingle(cmd, 0) );
//            SQLToken last = lastToken();
//            int length = last.offset + last.length - offset;
//            columns.add( new String( sql, offset, length ) );
//
////            token = nextToken(MISSING_COMMA_PARENTHESIS);
////            switch(token.value){
////                case smallsql.database.PARENTHESIS_R:
////                    break Loop;
////                case smallsql.database.COMMA:
////                    continue;
////                default:
////                    throw new Error();
////            }
//        }
//    }
//    

	/**
	 * Read a complex expression that can be build from multiple atomic expressions.
     * @param cmd is needed to add parameters "?" with addParameter() 
	 * @param previousOperationLevel the level of the left operation.
	 */
//    private Expression expression(Command cmd, int previousOperationLevel) throws SQLException{
//        SQLToken token = nextToken(MISSING_EXPRESSION);
//        Expression leftExpr;
////        switch(token.value){
////            case smallsql.database.NOT:
////            	leftExpr =  new ExpressionArithmetic( expression( cmd, ExpressionArithmetic.NOT      / 10), ExpressionArithmetic.NOT);
////            	break;
////            case smallsql.database.MINUS:
////            	leftExpr =  new ExpressionArithmetic( expression( cmd, ExpressionArithmetic.NEGATIVE / 10), ExpressionArithmetic.NEGATIVE);
////            	break;
////            case smallsql.database.TILDE:
////            	leftExpr =  new ExpressionArithmetic( expression( cmd, ExpressionArithmetic.BIT_NOT  / 10), ExpressionArithmetic.BIT_NOT);
////            	break;
////            case smallsql.database.PARENTHESIS_L:
////                leftExpr = expression( cmd, 0);
////                token = nextToken(MISSING_PARENTHESIS_R);
////                break;
////            default:
////                leftExpr = expressionSingle( cmd, token);
////        }
//        boolean isNot = false;
//        while((token = nextToken()) != null){
//            Expression rightExpr;
//            int operation = ExpressionArithmetic.getOperationFromToken(token.value);
//            int level = operation / 10;
//            if(previousOperationLevel >= level){
//                previousToken();
//                return leftExpr;
//            }
//            switch(token.value){
//                case smallsql.database.PLUS:
//                case smallsql.database.MINUS:
//                case smallsql.database.ASTERISK:
//                case smallsql.database.SLACH:
//                case smallsql.database.PERCENT:
//                case smallsql.database.EQUALS:
//                case smallsql.database.LESSER:
//                case smallsql.database.LESSER_EQU:
//                case smallsql.database.GREATER:
//                case smallsql.database.GREATER_EQU:
//                case smallsql.database.UNEQUALS:
//                case smallsql.database.LIKE:
//                case smallsql.database.OR:
//                case smallsql.database.AND:
//                case smallsql.database.BIT_AND:
//                case smallsql.database.BIT_OR:
//                case smallsql.database.BIT_XOR:
//                    rightExpr = expression( cmd, level );
//                    leftExpr = new ExpressionArithmetic( leftExpr, rightExpr, operation );
//                    break;
//                case smallsql.database.BETWEEN:
//                    rightExpr = expression( cmd, ExpressionArithmetic.AND );
//                    nextToken( MISSING_AND );
//                    Expression rightExpr2 = expression( cmd, level );
//                    leftExpr = new ExpressionArithmetic( leftExpr, rightExpr, rightExpr2, operation );
//                    break;
//                case smallsql.database.IN:
//            		nextToken(MISSING_PARENTHESIS_L);
//                	token = nextToken(MISSING_EXPRESSION);
//                	if(token.value == smallsql.database.SELECT){
//                		CommandSelect cmdSel = select();
//						leftExpr = new ExpressionInSelect( con, leftExpr, cmdSel, operation );
//						nextToken(MISSING_PARENTHESIS_R);
//                	}else{
//                		previousToken();
//                		Expressions list = expressionParenthesisList( cmd );
//                		leftExpr = new ExpressionArithmetic( leftExpr, list, operation );
//                	}
//                    break;
//                case smallsql.database.IS:
//                	token = nextToken(MISSING_NOT_NULL);
//                	if(token.value == smallsql.database.NOT){
//                		nextToken(MISSING_NULL);
//						operation++;
//                	}
//                	leftExpr = new ExpressionArithmetic( leftExpr, operation );
//                	break;
//                case smallsql.database.NOT:
//                	token = nextToken(MISSING_BETWEEN_IN);
//                	previousToken();
//                	isNot = true;
//                	continue;
//                default:
//                        previousToken();
//                        return leftExpr;
//            }
//            if(isNot){
//            	isNot = false;
//				leftExpr =  new ExpressionArithmetic( leftExpr, ExpressionArithmetic.NOT);
//            }
//        }
//        previousToken();
//        return leftExpr;
//    }

    /**
     * This method parse a single expression like 12, 'qwert', 0x3F or a column name.
     * 
     * @param cmd is needed to add parameters "?" with addParameter() 
     */
//    private Expression expressionSingle(Command cmd, int i) throws SQLException{
//        boolean isMinus = false;
//        if(i != null){
////            switch(token.value){
////                case smallsql.database.NULL:
////                        return new ExpressionValue( null, smallsql.database.NULL );
////                case smallsql.database.STRING:
////                        return new ExpressionValue( token.getName(null), smallsql.database.VARCHAR );
////                case smallsql.database.IDENTIFIER:
////                        {
////                        String name = getIdentifier( token );
////                        ExpressionName expr =  new ExpressionName( name );
////                        SQLToken token2 = nextToken();
////                        if(token2 != null && token2.value == smallsql.database.POINT){
////                            expr.setNameAfterTableAlias( nextIdentifier() );
////                        }else{
////                            previousToken();
////                        }
////                        return expr;
////                        }
////                case smallsql.database.TRUE:
////                        return new ExpressionValue( Boolean.TRUE, smallsql.database.BOOLEAN );
////                case smallsql.database.FALSE:
////                        return new ExpressionValue( Boolean.FALSE, smallsql.database.BOOLEAN );
////                case smallsql.database.ESCAPE_L:{
////                        token = nextToken(COMMANDS_ESCAPE);
////                        SQLToken para = nextToken(MISSING_EXPRESSION);
////                        Expression expr;
////                        switch(token.value){
////                            case smallsql.database.D: // date escape sequence
////                            	expr = new ExpressionValue( DateTime.valueOf(para.getName(sql), smallsql.database.DATE), smallsql.database.DATE );
////                            	break;
////                            case smallsql.database.T: // time escape sequence
////                                expr = new ExpressionValue( DateTime.valueOf(para.getName(sql), smallsql.database.TIME), smallsql.database.TIME );
////                            	break;
////                            case smallsql.database.TS: // timestamp escape sequence
////                                expr = new ExpressionValue( DateTime.valueOf(para.getName(sql), smallsql.database.TIMESTAMP), smallsql.database.TIMESTAMP );
////                            	break;
////                            case smallsql.database.FN: // function escape sequence
////                            	nextToken(MISSING_PARENTHESIS_L);
////                            	expr = function(cmd, para, true);
////                            	break;
////                            case smallsql.database.CALL: // call escape sequence
////                                throw new java.lang.UnsupportedOperationException("call escape sequence");
////                            default: throw new Error();
////                        }
////                        token = nextToken( ESCAPE_MISSING_CLOSE );
////                        return expr;
////                }
////                case smallsql.database.QUESTION:
////                        ExpressionValue param = new ExpressionValue();
////                        cmd.addParameter( param );
////                        return param;
////                case smallsql.database.CASE:
////                		return caseExpr(cmd);
////                case smallsql.database.MINUS:
////                case smallsql.database.PLUS:
////                        // sign detection
////                        do{
////                            if(token.value == smallsql.database.MINUS)
////                                    isMinus = !isMinus;
////                            token = nextToken();
////                            if(token == null) throw createSyntaxError( token, MISSING_EXPRESSION );
////                        }while(token.value == smallsql.database.MINUS || token.value == smallsql.database.PLUS);
////                        // no Break
////                default:
////                        SQLToken token2 = nextToken();
////                        if(token2 != null && token2.value == smallsql.database.PARENTHESIS_L){
////                            if(isMinus)
////                                return new ExpressionArithmetic( function( cmd, token, false ),  ExpressionArithmetic.NEGATIVE );
////                            return function( cmd, token, false );
////                        }else{
////                            // constant expression or identifier
////                            char chr1 = sql[ token.offset ];
////							if(chr1 == '$'){
////								previousToken();
////	                            String tok = new String(sql, token.offset+1, token.length-1);
////                                if(isMinus) tok = "-" + tok;
////								return new ExpressionValue( new Money(Double.parseDouble(tok)), smallsql.database.MONEY );
////							}
////                            String tok = new String(sql, token.offset, token.length);
////                            if((chr1 >= '0' && '9' >= chr1) || chr1 == '.'){
////                                previousToken();
////                                // first character is a digit
////                                if(token.length>1 && (sql[ token.offset +1 ] | 0x20) == 'x'){
////                                    // binary data as hex
////                                    if(isMinus) {
////                						throw createSyntaxError(token, Language.STXADD_OPER_MINUS);
////                                    }
////                                    return new ExpressionValue( Utils.hex2bytes( sql, token.offset+2, token.length-2), smallsql.database.VARBINARY );
////                                }
////                                if(isMinus) tok = "-" + tok;
////                                if(Utils.indexOf( '.', sql, token.offset, token.length ) >= 0 ||
////                                   Utils.indexOf( 'e', sql, token.offset, token.length ) >= 0){
////                                    return new ExpressionValue( new Double(tok), smallsql.database.DOUBLE );
////                                }else{
////                                    try{
////                                        return new ExpressionValue( new Integer(tok), smallsql.database.INT );
////                                    }catch(NumberFormatException e){
////                                        return new ExpressionValue( new Long(tok), smallsql.database.BIGINT );
////                                    }
////                                }
////                            }else{
////                                // identifier
////                                checkValidIdentifier( tok, token );
////                                ExpressionName expr = new ExpressionName(tok);
////                                if(token2 != null && token2.value == smallsql.database.POINT){
////                                    expr.setNameAfterTableAlias( nextIdentifier() );
////                                }else{
////                                    previousToken();
////                                }
////                                if(isMinus)
////                                    return new ExpressionArithmetic( expr,  ExpressionArithmetic.NEGATIVE );
////                                return expr;
////                            }
////                        }
////            }
//        }
//        return null;
//    }
    
    
    ExpressionFunctionCase caseExpr(final Command cmd) throws SQLException{
		ExpressionFunctionCase expr = new ExpressionFunctionCase();
		SQLToken token = nextToken(MISSING_EXPRESSION);
		
		Expression input = null;
//		if(token.value != smallsql.database.WHEN){
//			// simple CASE Syntax
//			previousToken();
//			input = expression(cmd, 0);
//			token = nextToken(MISSING_WHEN_ELSE_END);
//		}			
			
		while(true){
//			switch(token.value){
//				case smallsql.database.WHEN:				
//					Expression condition = expression(cmd, 0);
//					if(input != null){
//						// simple CASE Syntax
//						condition = new ExpressionArithmetic( input, condition, ExpressionArithmetic.EQUALS);
//					}
//					nextToken(MISSING_THEN);
//					Expression result = expression(cmd, 0);
//					expr.addCase(condition, result);
//					break;
//				case smallsql.database.ELSE:
//					expr.setElseResult(expression(cmd, 0));
//					break;
//				case smallsql.database.END:
//					expr.setEnd();
//					return expr;
//				default:
//					throw new Error();
//			}
//			token = nextToken(MISSING_WHEN_ELSE_END);
		}
    }
    

    /**
     * Parse any functions. The left parenthesis is already consumed from token list.
     * @param token the SQLToken of the function
     * @param isEscape If the function is a FN ESCAPE sequence
     */ 
//    private Expression function( Command cmd, SQLToken token, boolean isEscape ) throws SQLException{
//        Expression expr;
////        switch(token.value){
////        	case smallsql.database.CONVERT:{
////        		Column col;
////        		Expression style = null;
////        		if(isEscape){
////        			expr = expression( cmd, 0);
////					nextToken(MISSING_COMMA);
////					col = datatype(isEscape);
////        		}else{
////	        		col = datatype(isEscape);
////	        		nextToken(MISSING_COMMA);
////					expr = expression( cmd, 0);
////					token = nextToken(MISSING_COMMA_PARENTHESIS);
////					if(token.value == smallsql.database.COMMA){
////						style = expression( cmd, 0);
////					}else
////						previousToken();
////        		}
////        		nextToken(MISSING_PARENTHESIS_R);
////        		return new ExpressionFunctionConvert( col, expr, style );
////        	}
////        	case smallsql.database.CAST:
////        		expr = expression( cmd, 0);
////        		nextToken(MISSING_AS);
////        		Column col = datatype(false);
////        		nextToken(MISSING_PARENTHESIS_R);
////        		return new ExpressionFunctionConvert( col, expr, null );
////			case smallsql.database.TIMESTAMPDIFF:
////				token = nextToken(MISSING_INTERVALS);
////				nextToken(MISSING_COMMA);
////				expr = expression( cmd, 0);
////				nextToken(MISSING_COMMA);
////				expr = new ExpressionFunctionTimestampDiff( token.value, expr, expression( cmd, 0));
////				nextToken(MISSING_PARENTHESIS_R);
////				return expr;
////			case smallsql.database.TIMESTAMPADD:
////				token = nextToken(MISSING_INTERVALS);
////				nextToken(MISSING_COMMA);
////				expr = expression( cmd, 0);
////				nextToken(MISSING_COMMA);
////				expr = new ExpressionFunctionTimestampAdd( token.value, expr, expression( cmd, 0));
////				nextToken(MISSING_PARENTHESIS_R);
////				return expr;
////        }
//		Expressions paramList = expressionParenthesisList(cmd);
//        int paramCount = paramList.size();
//        Expression[] params = paramList.toArray();
//        boolean invalidParamCount;
//        switch(token.value){
//        // numeric functions:
//            case smallsql.database.ABS:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionAbs();
//                break;
//            case smallsql.database.ACOS:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionACos();
//                break;
//            case smallsql.database.ASIN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionASin();
//                break;
//            case smallsql.database.ATAN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionATan();
//                break;
//            case smallsql.database.ATAN2:
//                invalidParamCount = (paramCount != 2);
//                expr = new ExpressionFunctionATan2();
//                break;
//            case smallsql.database.CEILING:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionCeiling();
//                break;
//            case smallsql.database.COS:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionCos();
//                break;
//            case smallsql.database.COT:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionCot();
//                break;
//            case smallsql.database.DEGREES:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionDegrees();
//                break;
//            case smallsql.database.EXP:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionExp();
//                break;
//            case smallsql.database.FLOOR:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionFloor();
//                break;
//            case smallsql.database.LOG:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionLog();
//                break;
//            case smallsql.database.LOG10:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionLog10();
//                break;
//            case smallsql.database.MOD:
//                invalidParamCount = (paramCount != 2);
//                expr = new ExpressionFunctionMod();
//                break;
//            case smallsql.database.PI:
//                invalidParamCount = (paramCount != 0);
//                expr = new ExpressionFunctionPI();
//                break;
//            case smallsql.database.POWER:
//                invalidParamCount = (paramCount != 2);
//                expr = new ExpressionFunctionPower();
//                break;
//            case smallsql.database.RADIANS:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionRadians();
//                break;
//            case smallsql.database.RAND:
//                invalidParamCount =  (paramCount != 0) && (paramCount != 1);
//                expr = new ExpressionFunctionRand();
//                break;
//            case smallsql.database.ROUND:
//                invalidParamCount =  (paramCount != 2);
//                expr = new ExpressionFunctionRound();
//                break;
//            case smallsql.database.SIN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionSin();
//                break;
//            case smallsql.database.SIGN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionSign();
//                break;
//            case smallsql.database.SQRT:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionSqrt();
//                break;
//            case smallsql.database.TAN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionTan();
//                break;
//            case smallsql.database.TRUNCATE:
//                invalidParamCount =  (paramCount != 2);
//                expr = new ExpressionFunctionTruncate();
//                break;
//         
//        // string functions:
//			case smallsql.database.ASCII:
//				invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionAscii();
//				break;
//            case smallsql.database.BITLEN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionBitLen();
//                break;
//            case smallsql.database.CHARLEN:
//            case smallsql.database.CHARACTLEN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionCharLen();
//                break;
//			case smallsql.database.CHAR:
//				invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionChar();
//				break;
//            case smallsql.database.CONCAT:
//                if(paramCount != 2){
//                    invalidParamCount = true;
//                    expr = null;//only for compiler
//                    break;
//                }
//                invalidParamCount = false;
//                expr = new ExpressionArithmetic( params[0], params[1], ExpressionArithmetic.ADD);
//                break;
//            case smallsql.database.DIFFERENCE:
//                invalidParamCount = (paramCount != 2);
//                expr = new ExpressionFunctionDifference();
//                break;
//            case smallsql.database.INSERT:
//                invalidParamCount = (paramCount != 4);
//                expr = new ExpressionFunctionInsert();
//                break;
//            case smallsql.database.LCASE:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionLCase();
//                break;
//            case smallsql.database.LEFT:
//                invalidParamCount = (paramCount != 2);
//                expr = new ExpressionFunctionLeft();
//                break;
//			case smallsql.database.LENGTH:
//				invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionLength();
//				break;
//            case smallsql.database.LOCATE:
//            	invalidParamCount = (paramCount != 2) && (paramCount != 3);
//            	expr = new ExpressionFunctionLocate();
//            	break;
//            case smallsql.database.LTRIM:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionLTrim();
//                break;
//            case smallsql.database.OCTETLEN:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionOctetLen();
//                break;
//            case smallsql.database.REPEAT:
//                invalidParamCount = (paramCount != 2);
//                expr = new ExpressionFunctionRepeat();
//                break;
//            case smallsql.database.REPLACE:
//                invalidParamCount = (paramCount != 3);
//                expr = new ExpressionFunctionReplace();
//                break;
//			case smallsql.database.RIGHT:
//				invalidParamCount = (paramCount != 2);
//				expr = new ExpressionFunctionRight();
//				break;
//            case smallsql.database.RTRIM:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionRTrim();
//                break;
//            case smallsql.database.SPACE:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionSpace();
//                break;
//            case smallsql.database.SOUNDEX:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionSoundex();
//                break;
//			case smallsql.database.SUBSTRING:
//				invalidParamCount = (paramCount != 3);
//				expr = new ExpressionFunctionSubstring();
//				break;
//            case smallsql.database.UCASE:
//                invalidParamCount = (paramCount != 1);
//                expr = new ExpressionFunctionUCase();
//                break;
//                
//        // date time functions
//            case smallsql.database.CURDATE:
//            case smallsql.database.CURRENTDATE:
//            	invalidParamCount = (paramCount != 0);
//				expr = new ExpressionValue( new DateTime(DateTime.now(), smallsql.database.DATE), smallsql.database.DATE);
//				break;
//            case smallsql.database.CURTIME:
//            	invalidParamCount = (paramCount != 0);
//				expr = new ExpressionValue( new DateTime(DateTime.now(), smallsql.database.TIME), smallsql.database.TIME);
//				break;
//            case smallsql.database.DAYOFMONTH:
//            	invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionDayOfMonth();
//				break;
//            case smallsql.database.DAYOFWEEK:
//            	invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionDayOfWeek();
//				break;
//            case smallsql.database.DAYOFYEAR:
//            	invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionDayOfYear();
//				break;
//            case smallsql.database.HOUR:
//            	invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionHour();
//				break;
//            case smallsql.database.MINUTE:
//            	invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionMinute();
//				break;
//            case smallsql.database.MONTH:
//            	invalidParamCount = (paramCount != 1);
//				expr = new ExpressionFunctionMonth();
//				break;
//            case smallsql.database.NOW:
//            	invalidParamCount = (paramCount != 0);
//				expr = new ExpressionValue( new DateTime(DateTime.now(), smallsql.database.TIMESTAMP), smallsql.database.TIMESTAMP);
//				break;
//            	
//        // system functions:
//            case smallsql.database.IIF:
//        		invalidParamCount = (paramCount != 3);
//            	expr = new ExpressionFunctionIIF();
//        		break;
//        	case smallsql.database.SWITCH:
//        		invalidParamCount = (paramCount % 2 != 0);
//        		ExpressionFunctionCase exprCase = new ExpressionFunctionCase();
//        		for(int i=0; i < paramCount-1; i +=2)
//        			exprCase.addCase(params[i], params[i+1] );
//        		exprCase.setEnd();
//        		expr = exprCase;
//        		break;
//        	case smallsql.database.IFNULL:
//        		switch(paramCount){
//        			case 1:
//        				return new ExpressionArithmetic( params[0], ExpressionArithmetic.ISNULL );
//        			case 2:        				
//        				invalidParamCount = false;
//        				expr = new ExpressionFunctionIIF();
//        				Expression[] newParams = new Expression[3];
//        				newParams[0] = new ExpressionArithmetic( params[0], ExpressionArithmetic.ISNULL );
//        				newParams[1] = params[1];
//        				newParams[2] = params[0];        				
//        				params = newParams;
//        				paramCount = 3;
//        				break;
//        			default:
//        				invalidParamCount = true;
//        				expr = null; // only for Compiler
//        		}
//        		break;
//                    
//        // now come the aggregate functions
//            case smallsql.database.COUNT:
//					invalidParamCount = (paramCount != 1);
//					if(params[0].getType() == Expression.NAME){
//						//detect special case COUNT(*)
//						ExpressionName param = (ExpressionName)params[0];
//						if("*".equals(param.getName()) && param.getTableAlias() == null){
//                            //set any not NULL value as parameter
//							params[0] = new ExpressionValue("*", smallsql.database.VARCHAR);
//						}
//					}
//					expr = new ExpressionName( Expression.COUNT );
//					break;
//			case smallsql.database.SUM:
//					invalidParamCount = (paramCount != 1);
//					expr = new ExpressionName( Expression.SUM );
//					break;
//			case smallsql.database.MAX:
//					invalidParamCount = (paramCount != 1);
//					expr = new ExpressionName( Expression.MAX );
//					break;
//			case smallsql.database.MIN:
//					invalidParamCount = (paramCount != 1);
//					expr = new ExpressionName( Expression.MIN );
//					break;
//			case smallsql.database.FIRST:
//					invalidParamCount = (paramCount != 1);
//					expr = new ExpressionName( Expression.FIRST );
//					break;
//			case smallsql.database.LAST:
//					invalidParamCount = (paramCount != 1);
//					expr = new ExpressionName( Expression.LAST );
//					break;
//			case smallsql.database.AVG:
//					if(paramCount != 1){
//                        invalidParamCount = true;
//                        expr = null;//Only for the compiler
//                        break;
//                    }
//					expr = new ExpressionName( Expression.SUM );
//					expr.setParams( params );
//					Expression expr2 = new ExpressionName( Expression.COUNT );
//					expr2.setParams( params );
//					expr = new ExpressionArithmetic( expr, expr2, ExpressionArithmetic.DIV );
//					return expr;
//            default:
//            	throw createSyntaxError(token, Language.STXADD_FUNC_UNKNOWN);
//        }
//        if(invalidParamCount) {
//        	throw createSyntaxError(token, Language.STXADD_PARAM_INVALID_COUNT);
//        }
//        expr.setParams( params );
//        return expr;
//    }

    /**
     * read a table or view name in a FROM clause. If the keyword AS exists then read it also the alias
     */
    private RowSource tableSource( Command cmd, DataSources tables) throws SQLException{
        SQLToken token = nextToken(MISSING_EXPRESSION);
//        switch(token.value){
//            case smallsql.database.PARENTHESIS_L: // (
//                    return rowSource( cmd, tables, smallsql.database.PARENTHESIS_R );
//            case smallsql.database.ESCAPE_L: // {
//                    token = nextToken(MISSING_OJ);
//                    return rowSource( cmd, tables, smallsql.database.ESCAPE_R );
//            case smallsql.database.SELECT:
//            		// inner select
//            		ViewResult viewResult = new ViewResult( con, select() );
//            		tables.add(viewResult);
//            		return viewResult;
//        }
        String catalog = null;
        String name = getIdentifier( token );
		token = nextToken();
		//check if the table name include a database name
//		if(token != null && token.value == smallsql.database.POINT){
//			catalog = name;
//			name = nextIdentifier();
//			token = nextToken();
//		}
		//TableResult table = new TableResult();
		//table.setName( catalog, name );
		TableView tableView = Database.getTableView( con, catalog, name);
		TableViewResult table = TableViewResult.createResult(tableView);
        tables.add( table );

//        if(token != null && token.value == smallsql.database.AS){
//            // skip AS keyword, if exists
//            token = nextToken(MISSING_EXPRESSION);
//            table.setAlias( token.getName( sql ) );
//        }else{
//            previousToken();
//        }
        return table;
    }
    

    /**
     * read a join in a from clause.
     */
    private Join join(Command cmd, DataSources tables, RowSource left, int type) throws SQLException{
        RowSource right = rowSource(cmd, tables, 0);
        SQLToken token = nextToken();

        while(true){
            if(token == null) {
            	throw createSyntaxError(token, Language.STXADD_JOIN_INVALID);
            }

//            switch(token.value){
//            	case smallsql.database.ON:
//	            	if(type == Join.RIGHT_JOIN)
//						return new Join( Join.LEFT_JOIN, right, left, expression( cmd, 0 ) );
//	                return new Join( type, left, right, expression( cmd, 0 ) );
//	            default:
//	                if(!right.hasAlias()){
//	                    right.setAlias( token.getName( sql ) );
//	                    token = nextToken();
//	                    continue;
//	                }
//	                throw createSyntaxError( token, MISSING_ON );	                
//            }
        }
    }

    /**
     * returns a row source. A row source is a Table, Join, View or a row function.
     *
     */
    private RowSource rowSource(Command cmd, DataSources tables, int parenthesis) throws SQLException{
        RowSource fromSource = null;
        fromSource = tableSource(cmd, tables);

        while(true){
            SQLToken token = nextToken();
            if(token == null) return fromSource;
//            switch(token.value){
//                case smallsql.database.ON:
//                    previousToken();
//                    return fromSource;
//                case smallsql.database.CROSS:
//                    nextToken(MISSING_JOIN);
//                    //no break
//                case smallsql.database.COMMA:
//                    fromSource = new Join( Join.CROSS_JOIN, fromSource, rowSource(cmd, tables, 0), null);
//                    break;
//                case smallsql.database.INNER:
//                    nextToken(MISSING_JOIN);
//                    //no break;
//                case smallsql.database.JOIN:
//                    fromSource = join( cmd, tables, fromSource, Join.INNER_JOIN );
//                    break;
//                case smallsql.database.LEFT:
//                    token = nextToken(MISSING_OUTER_JOIN);
//                	if(token.value == smallsql.database.OUTER)
//                		token = nextToken(MISSING_JOIN);
//                    fromSource = join( cmd, tables, fromSource, Join.LEFT_JOIN );
//                    break;
//                case smallsql.database.RIGHT:
//                	token = nextToken(MISSING_OUTER_JOIN);
//                	if(token.value == smallsql.database.OUTER)
//                		token = nextToken(MISSING_JOIN);
//					fromSource = join( cmd, tables, fromSource, Join.RIGHT_JOIN );
//					break;                	
//				case smallsql.database.FULL:
//					token = nextToken(MISSING_OUTER_JOIN);
//					if(token.value == smallsql.database.OUTER)
//						token = nextToken(MISSING_JOIN);
//					fromSource = join( cmd, tables, fromSource, Join.FULL_JOIN );
//					break;                	
//                case smallsql.database.PARENTHESIS_R:
//                case smallsql.database.ESCAPE_R:
//                    if(parenthesis == token.value) return fromSource;
//                    if(parenthesis == 0){
//                    	previousToken();
//						return fromSource;
//                    }
//                    throw createSyntaxError( token, Language.STXADD_FROM_PAR_CLOSE );
//                default:
//                	if(isKeyword(token)){
//						previousToken();
//						return fromSource;
//                	}
//                    if(!fromSource.hasAlias()){
//                        fromSource.setAlias( token.getName( sql ) );
//                        break;
//                    }
//                    throw createSyntaxError( token, new int[]{smallsql.database.COMMA, smallsql.database.GROUP, smallsql.database.ORDER, smallsql.database.HAVING} );
//            }
        }
    }

//    private void from(CommandSelect cmd) throws SQLException{
//		DataSources tables = new DataSources();
//        cmd.setTables(tables);
//        cmd.setSource( rowSource( cmd, tables, 0 ) );
//
//		SQLToken token;
//        while(null != (token = nextToken())){
//            switch(token.value){
//                case Where:
//                    where( cmd );
//            		break;
//                case smallsql.database.GROUP:
//                    group( cmd );
//                    break;
//                case smallsql.database.HAVING:
//                    having( cmd );
//                    break;
//                default:
//                	previousToken();
//                    return;
//            }
//        }
//    }

//    private void order(CommandSelect cmd) throws SQLException{
//        nextToken(MISSING_BY);
//        cmd.setOrder(expressionTokenList(cmd, smallsql.database.ORDER));
//    }
    
//    private void limit(CommandSelect selCmd) throws SQLException{
//        SQLToken token = nextToken(MISSING_EXPRESSION);
//        try{
//            int maxRows = Integer.parseInt(token.getName(sql));
//            selCmd.setMaxRows(maxRows);
//        }catch(NumberFormatException e){
//            throw createSyntaxError(token, Language.STXADD_NOT_NUMBER, token.getName(sql));
//        }
//    }

//    private void group(CommandSelect cmd) throws SQLException{
//        int[] MISSING_BY;
//		nextToken(MISSING_BY);
//        cmd.setGroup( expressionTokenList(cmd, smallsql.database.GROUP) );
//    }

//    private void where(CommandSelect cmd) throws SQLException{
//        cmd.setWhere( expressionSingle(cmd, 0) );
//    }
//
//    private void having(CommandSelect cmd) throws SQLException{
//        cmd.setHaving( expressionSingle(cmd, 0) );
//    }


//    private static final int[] COMMANDS = {smallsql.database.SELECT, smallsql.database.DELETE, smallsql.database.INSERT, smallsql.database.UPDATE, smallsql.database.CREATE, smallsql.database.DROP, smallsql.database.ALTER, smallsql.database.SET, smallsql.database.USE, smallsql.database.EXECUTE, smallsql.database.TRUNCATE};
//    private static final int[] COMMANDS_ESCAPE = {smallsql.database.D, smallsql.database.T, T, smallsql.database.FN, smallsql.database.CALL};
//    private static final int[] COMMANDS_ALTER = {smallsql.database.DATABASE, smallsql.database.TABLE, smallsql.database.VIEW,  smallsql.database.PROCEDURE, };
//    private static final int[] COMMANDS_CREATE = {smallsql.database.DATABASE, smallsql.database.TABLE, smallsql.database.VIEW, smallsql.database.INDEX, smallsql.database.PROCEDURE, smallsql.database.UNIQUE, smallsql.database.CLUSTERED, smallsql.database.NONCLUSTERED};
//    private static final int[] COMMANDS_DROP = {smallsql.database.DATABASE, smallsql.database.TABLE, smallsql.database.VIEW, smallsql.database.INDEX, smallsql.database.PROCEDURE};
//    private static final int[] COMMANDS_SET = {smallsql.database.TRANSACTION};
//    private static final int[] COMMANDS_CREATE_UNIQUE = {smallsql.database.INDEX, smallsql.database.CLUSTERED, smallsql.database.NONCLUSTERED};
//	private static final int[] MISSING_TABLE = {smallsql.database.TABLE};
//    private static final int[] ESCAPE_MISSING_CLOSE = {smallsql.database.ESCAPE_R};
//    private static final int[] MISSING_EXPRESSION = {smallsql.database.VALUE};
//    private static final int[] MISSING_IDENTIFIER = {smallsql.database.IDENTIFIER};
//    private static final int[] MISSING_BY = {smallsql.database.BY};
//    private static final int[] MISSING_PARENTHESIS_L = {smallsql.database.PARENTHESIS_L};
//    private static final int[] MISSING_PARENTHESIS_R = {smallsql.database.PARENTHESIS_R};
//    private static final int[] MISSING_DATATYPE  = {smallsql.database.BIT, smallsql.database.BOOLEAN, smallsql.database.BINARY, smallsql.database.VARBINARY, smallsql.database.RAW, smallsql.database.LONGVARBINARY, smallsql.database.BLOB, smallsql.database.TINYINT, smallsql.database.SMALLINT, smallsql.database.INT, smallsql.database.COUNTER, smallsql.database.BIGINT, smallsql.database.SMALLMONEY, smallsql.database.MONEY, smallsql.database.DECIMAL, smallsql.database.NUMERIC, smallsql.database.REAL, smallsql.database.FLOAT, smallsql.database.DOUBLE, smallsql.database.DATE, smallsql.database.TIME, smallsql.database.TIMESTAMP, smallsql.database.SMALLDATETIME, smallsql.database.CHAR, smallsql.database.NCHAR, smallsql.database.VARCHAR, smallsql.database.NVARCHAR, smallsql.database.LONG, smallsql.database.LONGNVARCHAR, smallsql.database.LONGVARCHAR, smallsql.database.CLOB, smallsql.database.NCLOB, smallsql.database.UNIQUEIDENTIFIER, smallsql.database.JAVA_OBJECT, smallsql.database.SYSNAME};
//	private static final int[] MISSING_SQL_DATATYPE = { smallsql.database.SQL_BIGINT , smallsql.database.SQL_BINARY , smallsql.database.SQL_BIT , smallsql.database.SQL_CHAR , smallsql.database.SQL_DATE , smallsql.database.SQL_DECIMAL , smallsql.database.SQL_DOUBLE , smallsql.database.SQL_FLOAT , smallsql.database.SQL_INTEGER , smallsql.database.SQL_LONGVARBINARY , smallsql.database.SQL_LONGVARCHAR , smallsql.database.SQL_REAL , smallsql.database.SQL_SMALLINT , smallsql.database.SQL_TIME , smallsql.database.SQL_TIMESTAMP , smallsql.database.SQL_TINYINT , smallsql.database.SQL_VARBINARY , smallsql.database.SQL_VARCHAR };
//    private static final int[] MISSING_INTO = {smallsql.database.INTO};
//	private static final int[] MISSING_BETWEEN_IN = {smallsql.database.BETWEEN, Join};
//	private static final int[] MISSING_NOT_NULL = {smallsql.database.NOT, smallsql.database.NULL};
//    private static final int[] MISSING_NULL = {smallsql.database.NULL};
//	private static final int[] MISSING_COMMA = {smallsql.database.COMMA};
//    private static final int[] MISSING_COMMA_PARENTHESIS = {smallsql.database.COMMA, smallsql.database.PARENTHESIS_R};
//    private static final int[] MISSING_PARENTHESIS_VALUES_SELECT = {smallsql.database.PARENTHESIS_L, smallsql.database.VALUES, smallsql.database.SELECT};
//    private static final int[] MISSING_TOKEN_LIST = {smallsql.database.COMMA, smallsql.database.FROM, smallsql.database.GROUP, smallsql.database.HAVING, smallsql.database.ORDER};
//	private static final int[] MISSING_FROM = {smallsql.database.FROM};
//	private static final int[] MISSING_SET = {smallsql.database.SET};
//	private static final int[] MISSING_EQUALS = {smallsql.database.EQUALS};
//	private static final int[] MISSING_WHERE = {smallsql.database.WHERE};
//	private static final int[] MISSING_WHERE_COMMA = {smallsql.database.WHERE, smallsql.database.COMMA};
//    private static final int[] MISSING_ISOLATION = {smallsql.database.ISOLATION};
//    private static final int[] MISSING_LEVEL = {smallsql.database.LEVEL};
//    private static final int[] COMMANDS_TRANS_LEVEL = {smallsql.database.READ, smallsql.database.REPEATABLE, smallsql.database.SERIALIZABLE};
//    private static final int[] MISSING_READ = {smallsql.database.READ};
//    private static final int[] MISSING_COMM_UNCOMM = {smallsql.database.COMMITTED, smallsql.database.UNCOMMITTED};
//    private static final int[] MISSING_OPTIONS_DATATYPE = { smallsql.database.DEFAULT, smallsql.database.IDENTITY, smallsql.database.NOT, smallsql.database.NULL, smallsql.database.PRIMARY, smallsql.database.UNIQUE, smallsql.database.COMMA, smallsql.database.PARENTHESIS_R};
//    private static final int[] MISSING_NUMBERVALUE = {smallsql.database.NUMBERVALUE};
//    private static final int[] MISSING_AND = {smallsql.database.AND};
//    private static final int[] MISSING_JOIN = {smallsql.database.JOIN};
//    private static final int[] MISSING_OUTER_JOIN = {smallsql.database.OUTER, smallsql.database.JOIN};
//    private static final int[] MISSING_OJ = {smallsql.database.OJ};
//    private static final int[] MISSING_ON = {smallsql.database.ON};
//	private static final int[] MISSING_KEYTYPE = {smallsql.database.PRIMARY, smallsql.database.UNIQUE, smallsql.database.FOREIGN};
//	private static final int[] MISSING_KEY = {smallsql.database.KEY};
//    private static final int[] MISSING_REFERENCES = {smallsql.database.REFERENCES};
//	private static final int[] MISSING_AS = {smallsql.database.AS};
//	private static final int[] MISSING_SELECT = {smallsql.database.SELECT};
//	private static final int[] MISSING_INTERVALS = {smallsql.database.SQL_TSI_FRAC_SECOND, smallsql.database.SQL_TSI_SECOND, smallsql.database.SQL_TSI_MINUTE, smallsql.database.SQL_TSI_HOUR, smallsql.database.SQL_TSI_DAY, smallsql.database.SQL_TSI_WEEK, smallsql.database.SQL_TSI_MONTH, smallsql.database.SQL_TSI_QUARTER, smallsql.database.SQL_TSI_YEAR, smallsql.database.MILLISECOND, smallsql.database.SECOND, smallsql.database.MINUTE, smallsql.database.HOUR, smallsql.database.DAY, smallsql.database.WEEK, smallsql.database.MONTH, smallsql.database.QUARTER, smallsql.database.YEAR, smallsql.database.D};
//	private static final int[] MISSING_ALL = {smallsql.database.ALL};
//	private static final int[] MISSING_THEN = {smallsql.database.THEN};
//	private static final int[] MISSING_WHEN_ELSE_END = {smallsql.database.WHEN, smallsql.database.ELSE, smallsql.database.END};
//	private static final int[] MISSING_ADD_ALTER_DROP = {smallsql.database.ADD, smallsql.database.ALTER, smallsql.database.DROP};
//	
	
}